home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / B-C / Control Panel 0.9.5.sit / Control Panel Project 0.9.5 / MyPatch.c / MyPatch.c
Encoding:
C/C++ Source or Header  |  1994-10-06  |  13.2 KB  |  378 lines  |  [TEXT/KAHL]

  1. /*
  2.     MyPatch.c
  3.  
  4.     Written by Ken Worley, 10/04/94, using Symantec Think C 7.0.
  5.     Copyright 1994. All Rights Reserved.
  6.     
  7.     Feel free to use this code in a patch of your own.  Please don't
  8.     publish or distribute this code without giving me proper credit.
  9.     
  10.     This code is set up to use Apple's "Universal Headers."  If you're not
  11.     using those, some slight modifications may be necessary (changing
  12.     pointer types).
  13.     
  14.     This is the 'task' or 'patch' portion of the code.  The INIT or extension
  15.     portion of the code runs at system startup time, loads this piece of code into
  16.     memory, and installs it as a patch to a trap.
  17.     
  18.     This code shares a data structure with the extension portion of the code,
  19.     the control panel code, and possibly with other code as well.  One of the fields
  20.     in this shared data is called CPon.  This field is initially set by the
  21.     extension based on the values in the 'pref' resource.  The control panel code
  22.     may modify it later based on the user's choices in the control panel.  The
  23.     field determines whether we take action here, or jump to the original trap
  24.     without making any modifications.
  25.     
  26.     A pointer here is assigned to the address 0x12345678.  When the extension code
  27.     loads this code into memory, it replaces that bogus address with the address
  28.     of the shared data structure in memory.
  29.     
  30.     Using routines in the ANSI-A4 library (like vsprintf) requires that we set up
  31.     the A4 register here for access to globals.  Curiously, when I failed to do
  32.     that, the end result worked fine on my Performa 405 and crashed my Classic.
  33.     
  34.     BUILDING THE CODE RESOURCE
  35.     
  36.         This file should be included in a project of type 'code resource' with
  37.         MacTraps and ANSI-A4.  The resource type should be whatever is specified
  38.         in the MyExtension.c file (by a #define) and the ID should also be
  39.         whatever is specified in the MyExtension.c file (by a #define). The
  40.         resource attributes should indicate that this resource goes in the system
  41.         heap and that it should NOT be locked.
  42. */
  43.  
  44. /* PROTOTYPES */
  45.  
  46. void    main( void );
  47. Boolean    StrCompare( Str255 str1, Str255 str2 );
  48.  
  49. /* INCLUDED FILES */
  50.  
  51. #include "Notifier.h"        /* prototypes and includes for StrFormat and StrNotify */
  52.  
  53. #include "SharedData.h"        /* The definition of our shared data structure. */
  54.                             /* Includes definitions of myDataStruct, myDataPtr, */
  55.                             /* and myDataHandle to refer to this data. */
  56.  
  57. #include <Traps.h>            /* includes trap names like _BlockMove */
  58.  
  59. #include <SetUpA4.h>
  60.  
  61. /* FUNCTIONS */
  62.  
  63. void    main( void )
  64. {
  65.     myDataPtr        myData;            /* a pointer to our shared data */
  66.     long            oldTrapLoc;        /* local var to hold the old trap routine addr */
  67.     long            pBytes, rBytes;    /* vars for # of bytes in params & return val */
  68.     Boolean            callOriginal;    /* this determines whether we call orig trap */
  69.     Ptr                paramAddr;        /* set to the addr of the params on the stack */
  70.     Ptr                returnAddr;        /* set to the addr of the ret val on the stack */
  71.     Boolean            takeAction;        /* this flag determines whether this trap has */
  72.                                     /* any real effect */
  73.     
  74.     /*    Set up the A4 register for access to statics and globals. */
  75.     
  76.         RememberA0();
  77.         SetUpA4();
  78.         
  79.     /*    Here's where we assign a bogus address to our data structure pointer.
  80.      *    Again, this will be edited by the extension code so that it becomes a
  81.      *    valid address (using the Munger routine).  You won't need to change this.
  82.      */
  83.         
  84.         myData = (myDataPtr)(0x12345678);
  85.     
  86.     /*    Now wait until the shared data structure isn't in use, then flag it as
  87.      *    in use until we're through with it.
  88.      */
  89.      
  90.          while ( myData->inUse ) {}
  91.          myData->inUse = true;
  92.     
  93.     /*    Set the takeAction flag which will determine if our modifications get
  94.      *    executed or the old trap gets called and no modified code is executed.
  95.      */
  96.      
  97.          takeAction = myData->CPon;
  98.          
  99.     /*    Get the old trap location from the shared data structure.  Also get the
  100.      *    size of the parameters and return value for the trap.  You shouldn't need
  101.      *    to change this.
  102.      */
  103.     
  104.         oldTrapLoc = (long)myData->oldTrap;
  105.         pBytes = myData->paramBytes;
  106.         rBytes = myData->returnBytes;
  107.     
  108.     /*    Get the addresses of the parameters sent to the trap and the space reserved
  109.      *    on the stack for the return value.  We can find these as an offset from A6.
  110.      *    The address of the parameters goes into paramAddr and the address of the
  111.      *    space reserved for the return value goes into returnAddr.  You shouldn't
  112.      *    need to change this (even if it's a register based routine in which case the
  113.      *    values would have no meaning).
  114.      */
  115.      
  116.          asm {
  117.              MOVE.L    A6,A0            ;copy A6 into A0
  118.              ADD.L    #8,A0            ;add 8 to get addr of original params
  119.              MOVE.L    A0,paramAddr    ;copy addr of params into local var paramAddr
  120.              ADD.L    pBytes,A0        ;add # of param bytes to get addr of ret value
  121.              MOVE.L    A0,returnAddr    ;copy addr of ret value into local var returnAddr
  122.          }
  123.  
  124.     /*    Any changes to the original parameters should be done here (usually if the
  125.      *    original trap is going to be called).  Also, changes to the return value
  126.      *    can be made here (usually when the original trap is NOT going to be called).
  127.      *    The local var returnAddr is a pointer to the place in the stack where the
  128.      *    return value is.  Remember, before we call the original trap there is no
  129.      *    return value...only a space for one so the value is undefined.  If we're not
  130.      *    going to call the original trap, then we can set the return value here to
  131.      *    whatever we want to be returned to the calling program.  If you modify the
  132.      *    return value here, then call the original trap, the value will be overwritten
  133.      *    with the value returned from the original trap.  The easiest way to access
  134.      *    the return value would be to declare a local variable as a pointer to
  135.      *    whatever the return type is, then assign returnAddr to that variable casting
  136.      *    it to a pointer to the correct type.
  137.      */
  138.     
  139.         if ( takeAction )
  140.         {
  141.         
  142.             /*    I don't do anything with the parameters before the original trap
  143.              *    is called in this case :-).
  144.              *
  145.              *    Example:  If the return value was a Point (same size as a long, 4 bytes)
  146.              *    then we could easily access it as follows:
  147.              *
  148.              *    Declare a local variable at the beginning of main like so:
  149.              *
  150.              *        Point    *myPoint;
  151.              *
  152.              *    Then assign returnAddr to myPoint casting it as a pointer to a Point:
  153.              *
  154.              *        myPoint = (Point*)returnAddr;
  155.              *        
  156.              *    Now we can access the value:
  157.              *
  158.              *        myPoint->h = whatever;
  159.              */
  160.              
  161.          }
  162.     
  163.     /*    Set callOriginal so that the original trap will be called.  You may want to
  164.      *    change this so that callOriginal is set based on certain conditions.  I just
  165.      *    set it to true here so that the original trap is called.  You may want to
  166.      *    just set it to false to avoid calling the original trap if you set the
  167.      *    return value yourself or just don't want the trap to have any effect (when
  168.      *    there is no return value).
  169.      */
  170.     
  171.         callOriginal = true;
  172.     
  173.     /*    If the callOriginal flag is true OR if we're not supposed to take any action
  174.      *    here, call the original trap.
  175.      */
  176.      
  177.     if ( callOriginal || !takeAction )
  178.     {
  179.         Ptr    topOfStack;
  180.         
  181.         /*    Make space for a return value (if any) and copy the original parameters to
  182.          *    the top of the stack.  Then jump to the old trap location using JSR so
  183.          *    that execution will return here.  You shouldn't need to change this.
  184.          */
  185.      
  186.              asm {
  187.                  SUB.L    rBytes,SP        ;make space on stack for return value
  188.                  SUB.L    pBytes,SP        ;make space for parameters on stack
  189.                  
  190.                  MOVE.L    SP,topOfStack    ;save addr of top of stack in a local var
  191.              }
  192.              
  193.              BlockMove( paramAddr, topOfStack, pBytes ); /* copy orig params to */
  194.                                                          /* top of stack */
  195.              asm {
  196.                  MOVE.L    oldTrapLoc,A0    ;put addr of orig trap into A0
  197.                  JSR        (A0)            ;jump to the original trap
  198.              }
  199.  
  200.         /*    Execution returns here after calling the original trap and the function
  201.           *    result is left on top of the stack.  Copy the new result into the space
  202.           *    allocated for the result when we were originally called, then pop the
  203.           *    new result value off the stack.
  204.           *    This code only executes if there is a return value (if rBytes is nonzero).
  205.           *    You shouldn't need to change this.
  206.           */
  207.               
  208.               if ( rBytes )
  209.               {
  210.                   asm {
  211.                       MOVE.L    SP,topOfStack        ;get addr of top of stack (source)
  212.                   }
  213.                   
  214.                   BlockMove( topOfStack, returnAddr, rBytes );
  215.  
  216.                 asm {
  217.                     ADD.L    rBytes,SP            ;pop new return value off stack
  218.                   }
  219.               }
  220.      }    /* end if ( callOriginal || !takeAction ) */
  221.      
  222.     /*    If you need to modify the return value, do so here.  Its addr is still in
  223.      *    returnAddr.  If the original trap was called, the value it returned (if any)
  224.      *    was copied to returnAddr.  Also, paramAddr does still point to the parameters
  225.      *    if you need to access them still.  Modifying them at this point, however, would
  226.      *    have no effect since we're just about to pop them off the stack into oblivion.
  227.      *    Remember if it was a pointer or handle that was sent as a parameter, that value
  228.      *    won't have changed, but the data that it points to may have.  If you did NOT
  229.      *    call the original trap and do NOT modify the return value here, and there IS
  230.      *    a return value, you'll be returning GARBAGE to the calling program (bad idea).
  231.      *
  232.      *    I believe that taking action at this point is what's known as a "tail patch"
  233.      *    which is generally considered to be "ill-advised."  The way this is set up,
  234.      *    however, I don't see how anything unforseen could happen as long as we're
  235.      *    careful.
  236.      */
  237.      
  238.      if ( takeAction )
  239.      {
  240.      
  241.          /*    The return value from MenuSelect is a long integer value whose high word
  242.           *    contains the menu id (zero if none selected) and whose low word contains
  243.           *    the item number selected in that menu (undefined if none selected).
  244.           *    Here I check to see if the menu item selected was "About This Macintosh..."
  245.           *    and if it was, I put up a Notification to brag about our hacking prowess.
  246.           *    Then I return the return value unchanged and the Macintosh info dialog
  247.           *    will come up.
  248.           */
  249.           
  250.               {    /* isolate our code and variables here in a block for neatness' sake */
  251.               
  252.                   short        *menuInfo;
  253.                   MenuHandle    menuH;
  254.                   Str255        itemString;
  255.                   Str255        compString = "\pAbout This Macintosh…";
  256.                   
  257.                   /* By the way, the three dots at the end of some menu items are NOT */
  258.                   /* three periods, they are one character--an option semi-colon */
  259.                   
  260.               /*    Assign returnAddr to menuInfo - a pointer to a short */
  261.               
  262.                   menuInfo = (short*)returnAddr;
  263.               
  264.               /*    Now we can use menuInfo[0] to access the high word (menu id#)
  265.                *    and menuInfo[1] to access the low word (the item#).
  266.                */
  267.                    if ( menuInfo[0] )    /* if a menu item was selected, will be nonzero */
  268.                    {
  269.                        menuH = GetMHandle( menuInfo[0] );    /* get a handle to the menu */
  270.                        GetItem( menuH, menuInfo[1], itemString );    /* get menu item text */
  271.                        
  272.                        if ( StrCompare( itemString, compString ) )
  273.                        {
  274.                            /* Here's an example of using the Notification manager through
  275.                             * the StrFormat and StrNotify routines.  StrFormat works like
  276.                             * printf.  Do NOT put a "\p" at the beginning of the string.
  277.                             */
  278.                         StrFormat( myData->str, "Ha! Ha!  Hackers do it "
  279.                             "at system level!  "
  280.                             "Menu #%d, Item #%d.", menuInfo[0], menuInfo[1] );
  281.                         StrNotify( &(myData->nm), &(myData->str) );
  282.                        }
  283.                    }
  284.               }
  285.               
  286.      }    /* end if ( myData->patchAction )
  287.      
  288.      /*    Now we're through with the shared data */
  289.      
  290.          myData->inUse = false;
  291.      
  292.      /* Restore the A4 register to its previous value */
  293.      
  294.          RestoreA4();
  295.          
  296.      /*    Finish up by unlinking A6 (Think C automatically links A6 on entry
  297.       *    to the routine.  It also unlinks it automatically at the end of the routine,
  298.       *    but we're going to jump out before the actual end of the routine.),
  299.       *    removing the original parameters from the stack, and jumping to the return
  300.       *    address.  You shouldn't need to change this.
  301.       */
  302.           
  303.           asm {
  304.               MOVE.L    pBytes,D0    ;save the number of bytes in the parameters into D0
  305.               UNLK    A6            ;unlinking leaves return addr at the top of the stack
  306.               MOVE.L    (SP)+,A0    ;move return address to register A0
  307.               ADD.L    D0,SP        ;pop old parameters off stack
  308.               JMP        (A0)        ;jump to the return address
  309.           }
  310. }
  311.  
  312. #include "Notifier.c"    /* contains StrFormat and StrNotify */
  313.  
  314. Boolean    StrCompare( Str255 str1, Str255 str2 )
  315. {
  316.     /*    This function returns true if the two strings sent are equal.  The comparison
  317.      *    is case sensitive and trailing blanks are ignored.  If one string is longer
  318.      *    and contains something OTHER than blanks after the end of the other string,
  319.      *    the function will return false.
  320.      */
  321.  
  322.     short    shorter,    /* which string is shorter? */
  323.             endShort,    /* last character of the shorter string */
  324.             endLong;    /* last character of the longer string */
  325.     Boolean    result;
  326.     
  327.     result = true;    /* assume they're equal until we find otherwise */
  328.     
  329.     shorter = 1;
  330.     endShort = str1[0];
  331.     endLong = str2[0];
  332.     
  333.     if ( str2[0] < str1[0] )
  334.     {
  335.         shorter = 2;
  336.         endShort = str2[0];
  337.         endLong = str1[0];
  338.     }
  339.     
  340.     {                /* check each letter to see if they're equal */
  341.         short x;
  342.         for ( x = 1; x <= endShort; x++ )
  343.         {
  344.             if ( str1[x] != str2[x] )
  345.             {
  346.                 result = false;    /* not equal */
  347.                 break;
  348.             }
  349.         }
  350.     }
  351.     
  352.     if ( result )    /* check for non-blank trailing characters */
  353.     {
  354.         short x;
  355.         for ( x = endShort+1; x <= endLong; x++ )
  356.         {
  357.             if ( shorter == 1 )
  358.             {
  359.                 if ( str2[x] != ' ' )
  360.                 {
  361.                     result = false;    /* not a blank */
  362.                     break;
  363.                 }
  364.             }
  365.             else
  366.             {
  367.                 if ( str1[x] != ' ' )
  368.                 {
  369.                     result = false; /* not a blank */
  370.                     break;
  371.                 }
  372.             }
  373.         }
  374.     }
  375.     return result;
  376. }
  377.  
  378.